iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
Software Development

當rust 遇上 cqrs & es系列 第 8

D8 實現基本資料結構(3)

  • 分享至 

  • xImage
  •  

之前實作的reader有點不完整,調整一下

讀者

const MAX_BOOKS_PER_READER: usize = 5;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reader {
    pub id: String,
    pub name: String,
    pub borrowed_books: Vec<BorrowedBook>,
    pub borrowed_history: Vec<BorrowedBook>,
}

借閱紀錄

#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct BorrowedBook {
    pub book_id: String,
    pub borrowed_date: DateTime<Utc>,
    pub due_date: DateTime<Utc>,
    pub return_date: Option<DateTime<Utc>>,
}

command:

pub enum ReaderCommand {
    CreateReader { name: String },
    BorrowBook {
        book_id: String,
        borrowed_date: DateTime<Utc>,
        due_date: DateTime<Utc>,
    },
    ReturnBook {
        book_id: String,
        return_date: DateTime<Utc>,
    },
}

event:

pub enum ReaderEvent {
    ReaderCreated { name: String, id: String },
    BookBorrowed(BorrowedBook),
    BookReturned(BorrowedBook),
}

實作Reader的handle:

ReaderCommand::BorrowBook { book_id, borrowed_date, due_date } => {
    if self.borrowed_books.len() >= MAX_BOOKS_PER_READER {
        return Err(ReaderError(format!("讀者最多只能借 {} 本書", MAX_BOOKS_PER_READER)));
    }
    if self.borrowed_books.iter().any(|b| b.book_id == book_id) {
        return Err(ReaderError("讀者已借出同一本書".to_string()));
    }
    let event = ReaderEvent::BookBorrowed(
        BorrowedBook {
            book_id,
            borrowed_date,
            due_date,
            return_date: None,
        });
    Ok(vec![event])
}
ReaderCommand::ReturnBook { book_id, return_date } => {
    let borrowed_book =
        self.borrowed_books
            .iter()
            .find(|b|
                b.book_id == book_id
                    && b.return_date.is_none());
    if borrowed_book.is_none() {
        return Err(ReaderError("讀者未借出此書".to_string()));
    }
    let borrowed_book = borrowed_book.unwrap();
    let event = ReaderEvent::BookReturned(
        BorrowedBook {
            book_id: borrowed_book.book_id.clone(),
            borrowed_date: borrowed_book.borrowed_date,
            due_date: borrowed_book.due_date,
            return_date: Some(return_date),
        });
    Ok(vec![event])
}

實作Reader的apply

ReaderEvent::BookBorrowed(record) => {
    self.borrowed_books.push(record);
}
ReaderEvent::BookReturned(record) => {
    self.borrowed_books.retain(|b|
        b.book_id != record.book_id && b.borrowed_date != record.borrowed_date);
    let record = BorrowedBook {
        book_id: record.book_id,
        borrowed_date: record.borrowed_date,
        due_date: record.due_date,
        return_date: Some(DateTime::from(Utc::now())),
    };
    self.borrowed_history.push(record);
}

實作Reader的rollabck

ReaderEvent::ReaderCreated { .. } => {
    self.name = String::new();
}
ReaderEvent::BookBorrowed(record) => {
    self.borrowed_books.retain(|b|
        b.book_id != record.book_id && b.borrowed_date != record.borrowed_date);
}
ReaderEvent::BookReturned(record) => {
    self.borrowed_history.retain(|b|
        b.book_id != record.book_id && b.borrowed_date != record.borrowed_date);
    self.borrowed_books.push(BorrowedBook {
        book_id: record.book_id,
        borrowed_date: record.borrowed_date,
        due_date: record.due_date,
        return_date: None,
    });
}

上一篇
D7 ~~測試~~ 用 es 存放 book 事件
下一篇
D9 測試 reader event store
系列文
當rust 遇上 cqrs & es30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言